package org.yi.fc.security.shiro;

import java.io.IOException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.PathMatchingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yi.fc.common.Constants;


public class FormLoginFilter extends PathMatchingFilter {
	
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private Subject subjet = null;
	
    private String loginUrl = "/admin/login";
    private String successUrl = "/admin";

    @Override
    protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
    	subjet = SecurityUtils.getSubject();
    	
    	if(subjet.isAuthenticated()) {
            return true;//已经登录过
        }
        
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        
        if(isLoginRequest(req)) {
        	if("POST".equalsIgnoreCase(req.getMethod())) {//form表单提交
        		
        		if(!doCaptchaValidate(request)){
        			return redirectToFailUrl(req, resp);
        		}
        		
                boolean loginSuccess = login(req); //登录
                if(loginSuccess) {
                    return redirectToSuccessUrl(req, resp);
                }
            }
        	
            return true;//继续过滤器链
            
        } else {//保存当前地址并重定向到登录界面
            saveRequestAndRedirectToLogin(req, resp);
            return false;
        }
    }

    private boolean redirectToSuccessUrl(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        WebUtils.redirectToSavedRequest(req, resp, successUrl);
        return false;
    }
    
    private boolean redirectToFailUrl(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        WebUtils.redirectToSavedRequest(req, resp, loginUrl);
        return false;
    }

    private void saveRequestAndRedirectToLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        WebUtils.saveRequest(req);
        WebUtils.issueRedirect(req, resp, loginUrl);
    }

    private boolean login(HttpServletRequest req) {
    	
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        
        try {
            subjet.login(new UsernamePasswordToken(username, password));
        } catch (Exception e) {
            req.setAttribute("shiroLoginFailure", "账户或密码错误");
            return false;
        }
        
        return true;
    }

    private boolean isLoginRequest(HttpServletRequest req) {
        return pathsMatch(loginUrl, WebUtils.getPathWithinApplication(req));
    }
    
    
    /**
	 * 获取客户端验证码
	 * @param request
	 * @param captchKey 
	 * @return
	 */
	private final String getClientCapthcaCode(ServletRequest request){
		return WebUtils.getCleanParam(request, Constants.VERIFY_CODE);
	}
	
	/**
	 * 获取服务器端生成的验证码
	 * @param request
	 * @return
	 */
	private final String getServerCapthcCode(ServletRequest request){
		return String.valueOf(subjet.getSession().getAttribute(Constants.VERIFY_CODE));
	}
	
	/**
	 * 验证校验码
	 * @param request
	 * @param captchKey			验证码key
	 * @return
	 */
	private boolean doCaptchaValidate(ServletRequest request) throws AuthenticationException {
		String clientCode = getClientCapthcaCode(request);
		String serverCode = getServerCapthcCode(request);
		
		if(clientCode == null || serverCode == null){
			logger.error("验证码验证失败，客户端验证码【{}】或者服务端验证码【{}】为空", clientCode, serverCode);
			return false;
		}
		
		if( clientCode.equalsIgnoreCase(serverCode) ){
			return true;
		}else{
			logger.error("验证码验证失败，客户端验证码【{}】,服务端验证码【{}】", clientCode, serverCode);
			return false;
		}
		
	}
    
}
